#pragma once
#include <algorithm>
#include "Index.hpp"
#include "util.hpp"
#include "log.hpp"
#include <jsoncpp/json/json.h>

using namespace ns_index;
using namespace ns_util;

namespace ns_search
{
	class Searcher
	{
	private:
		ns_index::Index *index;

	public:
		Searcher(){}
		~Searcher(){}

		struct InvertedElemPrint{
			uint64_t doc_id;
			int weight;
			std::vector<std::string> words;
		};

		void InitSearch(const std::string& input){
			// 1.获取或构建index对象
			index = ns_index::Index::GetInstance();
			// std::cout << "获取index单例对象成功..." << std::endl;
			LOG(NORMAL, "获取index单例对象成功...");

			// 2.根据index对象建立索引
			index->BuildIndex(input);
			// std::cout << "构建索引成功" << std::endl;
			LOG(NORMAL, "构建索引成功");
		}

		// query为用户输入的查询字符串，json_string为返回给用户的搜索结果
		void Search(const std::string& query, std::string* json_string){
			// 1.【分词】：对query按照Searcher要求进行分词
			std::vector<std::string> words;
			ns_util::JiebaUtil::CutString(query, &words);

			std::unordered_map<uint64_t, InvertedElemPrint> tokens_map;
			
			std::vector<InvertedElemPrint> invert_list_all;
			// 2.【触发】就是根据分词的各个词，进行index查找
			for(auto& word : words){
				boost::to_lower(word);
				Invert_t* invert_list = index->GetInvertedList(word);
				if(invert_list == nullptr)
					continue;

				for(const auto& elem : *invert_list){
					auto& item = tokens_map[elem.doc_id];
					item.doc_id = elem.doc_id;
					item.weight += elem.weight;
					item.words.push_back(elem.word);
				}
			}

			// 遍历文档总权重hash表，放入每一个文档的权重
			for(const auto& item : tokens_map){
				invert_list_all.push_back(std::move(item.second));
			}

			// 3.【合并排序】汇总查找结果，按照相关性weight降序排序
			std::sort(invert_list_all.begin(), invert_list_all.end(), [](const InvertedElemPrint& a, const InvertedElemPrint& b){
				return a.weight > b.weight;
			});

			// 4.【构建】根据查找出来的结果构建json串jsoncpp
			Json::Value root;
			for(auto& item : invert_list_all){
				DocInfo* doc = index->GetForwardIndex(item.doc_id);
				if(doc == nullptr)
					continue;

				Json::Value elem;
				elem["title"] = doc->title;
				elem["desc"] = GetDesc(doc->content, item.words[0]); // 后续将对内容进行归纳描述
				elem["url"] = doc->url;
				// elem["id"] = (int)doc->doc_id;
				// elem["weight"] = item.weight;

				root.append(elem);
			}

			Json::FastWriter writer;
			*json_string = writer.write(root);
		}

		std::string GetDesc(const std::string& html_content, const std::string& word){
			int prev_step = 50;
			int next_step = 100;

			// 找到首次出现
			auto item = std::search(html_content.begin(), html_content.end(), word.begin(), word.end(), [](int a, int b){
				return tolower(a) == tolower(b);
			});

			if(item == html_content.end())
				return "None";

			int pos = std::distance(html_content.begin(), item);
			
			// 获取start end
			int start = 0;
			int end = html_content.size() - 1;
			if(pos - prev_step > start)
				start = pos - prev_step;
			if(pos + next_step < end)
				end = pos + next_step;

			if(start >= end)
				return "None";

			// 截取子串并return 
			return html_content.substr(start, end - start) + "...";
		}
	};
}